/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef __VFS_H__
#define __VFS_H__

/* includes (standard library, system) ---------------------------------------*/
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>

#include <sys/fcntl.h>
#include <sys/stat.h>
/* includes (other library) --------------------------------------------------*/
#include <x_config.h>
#if defined(CONFIG_OS_LINUX) && defined(CONFIG_FATFS)
// fix error: conflicting types for ‘DIR’
#include <posix/dirent.h>
#else
#include <dirent.h>
#endif
/* includes (project) --------------------------------------------------------*/
#include <x_list.h>
#include <kal.h>
/* includes (local) ----------------------------------------------------------*/

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/

/* forward declaraton */
struct file;
struct dir;
struct mount_point;

struct f_ops {
    int (*open)(struct file *fp, const char *path, int flags, int mode);
    int (*close)(struct file *fp);
    int (*read)(struct file *fp, char *buf, size_t nbyte);
    int (*write)(struct file *fp, const char *buf, size_t nbyte);
    int (*lseek)(struct file *fp, int offset, int whence);
    int (*ioctl)(struct file *fp, int request, va_list valist);
    int (*sync)(struct file *fp);
};

struct m_ops {
    int (*stat)(struct mount_point *mp, const char *path, struct stat *st);
    int (*unlink)(struct mount_point *mp, const char *path);
    int (*rename)(struct mount_point *mp, const char *oldname, const char *newname);
    int (*opendir)(struct mount_point *mp, struct dir *dp, const char *path);
    int (*readdir)(struct mount_point *mp, struct dir *dp, struct dirent *de);
    int (*closedir)(struct mount_point *mp, struct dir *dp);
    int (*mkdir)(struct mount_point *mp, const char *path, int mode);
    int (*rmdir)(struct mount_point *mp, const char *path);
    int (*mount)(struct mount_point *mp, va_list valist);
    int (*unmount)(struct mount_point *mp, va_list valist);
};

struct file_system {
    const char *fs_name;

    const struct f_ops *fs_fops;
    const struct m_ops *fs_mops;

    dlist_t fs_node;
    volatile uint32_t fs_refs;
};

struct mount_point {
    struct file_system *mp_fs;
    char *mp_path;
    dlist_t mp_node;
    k_mutex_t mp_lock;
    volatile uint32_t mp_refs;
    uintptr_t mp_data;
};

struct file {
    const struct f_ops *fl_fops;
    int fl_flags;
    struct mount_point *fl_mp;
    volatile uint32_t fl_refs;
    uintptr_t fl_data;
    char *fl_path;
};

/* file descriptor */
struct fildes {
    struct file *fd_file;
    int fd_flags;
    bool fd_used;
};

struct dir {
    struct mount_point *dr_mp;
    struct dirent dr_dent;
    uintptr_t dr_data;
};

/* macro ---------------------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* externs -------------------------------------------------------------------*/

extern int vfs_open(const char *path, int flags, ...);
extern int vfs_close(int fd);
extern int vfs_read(int fd, char *buf, size_t nbyte);
extern int vfs_write(int fd, const char *buf, size_t nbyte);
extern int vfs_lseek(int fd, int offset, int whence);
extern int vfs_ioctl(int fd, int req, ...);
extern int vfs_sync(int fd);
extern int vfs_stat(const char *path, struct stat *stat);
extern int vfs_unlink(const char *path);
extern int vfs_rename(const char *oldname, const char *newname);
extern struct dir *vfs_opendir(const char *path);
extern struct dirent *vfs_readdir(struct dir *dp);
extern int vfs_closedir(struct dir *dp);
extern int vfs_mkdir(const char *path, int mode);
extern int vfs_rmdir(const char *path);
extern int vfs_mount(const char *fs_name, const char *mp_path, ...);
extern int vfs_unmount(const char *path, ...);
extern int vfs_fs_register(struct file_system *fs);
extern int vfs_fs_unregister(struct file_system *fs);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __VFS_H__ */
